home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / lib / firefox-3.5.5 / components / nsPlacesTransactionsService.js < prev    next >
Text File  |  2009-11-09  |  40KB  |  1,117 lines

  1. /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* ***** BEGIN LICENSE BLOCK *****
  3.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  4.  *
  5.  * The contents of this file are subject to the Mozilla Public License Version
  6.  * 1.1 (the "License"); you may not use this file except in compliance with
  7.  * the License. You may obtain a copy of the License at
  8.  * http://www.mozilla.org/MPL/
  9.  *
  10.  * Software distributed under the License is distributed on an "AS IS" basis,
  11.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12.  * for the specific language governing rights and limitations under the
  13.  * License.
  14.  *
  15.  * The Original Code is the Places Command Controller.
  16.  *
  17.  * The Initial Developer of the Original Code is Google Inc.
  18.  *
  19.  * Portions created by the Initial Developer are Copyright (C) 2005
  20.  * the Initial Developer. All Rights Reserved.
  21.  *
  22.  * Contributor(s):
  23.  *   Sungjoon Steve Won <stevewon@gmail.com> (Original Author)
  24.  *   Asaf Romano <mano@mozilla.com>
  25.  *   Marco Bonarco <mak77@bonardo.net>
  26.  *
  27.  * Alternatively, the contents of this file may be used under the terms of
  28.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  29.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  30.  * in which case the provisions of the GPL or the LGPL are applicable instead
  31.  * of those above. If you wish to allow use of your version of this file only
  32.  * under the terms of either the GPL or the LGPL, and not to allow others to
  33.  * use your version of this file under the terms of the MPL, indicate your
  34.  * decision by deleting the provisions above and replace them with the notice
  35.  * and other provisions required by the GPL or the LGPL. If you do not delete
  36.  * the provisions above, a recipient may use your version of this file under
  37.  * the terms of any one of the MPL, the GPL or the LGPL.
  38.  *
  39.  * ***** END LICENSE BLOCK ***** */
  40.  
  41. let Ci = Components.interfaces;
  42. let Cc = Components.classes;
  43. let Cr = Components.results;
  44.  
  45. const LOAD_IN_SIDEBAR_ANNO = "bookmarkProperties/loadInSidebar";
  46. const DESCRIPTION_ANNO = "bookmarkProperties/description";
  47.  
  48. const CLASS_ID = Components.ID("c0844a84-5a12-4808-80a8-809cb002bb4f");
  49. const CONTRACT_ID = "@mozilla.org/browser/placesTransactionsService;1";
  50.  
  51. Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
  52.  
  53. __defineGetter__("PlacesUtils", function() {
  54.   delete this.PlacesUtils
  55.   var tmpScope = {};
  56.   Components.utils.import("resource://gre/modules/utils.js", tmpScope);
  57.   return this.PlacesUtils = tmpScope.PlacesUtils;
  58. });
  59.  
  60. // The minimum amount of transactions we should tell our observers to begin
  61. // batching (rather than letting them do incremental drawing).
  62. const MIN_TRANSACTIONS_FOR_BATCH = 5;
  63.  
  64. function placesTransactionsService() {
  65.   this.mTransactionManager = Cc["@mozilla.org/transactionmanager;1"].
  66.                              createInstance(Ci.nsITransactionManager);
  67. }
  68.  
  69. placesTransactionsService.prototype = {
  70.   classDescription: "Places Transaction Manager",
  71.   classID: CLASS_ID,
  72.   contractID: CONTRACT_ID,
  73.  
  74.   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPlacesTransactionsService,
  75.                                          Ci.nsITransactionManager]),
  76.  
  77.   aggregateTransactions:
  78.   function placesTxn_aggregateTransactions(aName, aTransactions) {
  79.     return new placesAggregateTransactions(aName, aTransactions);
  80.   },
  81.  
  82.   createFolder:
  83.   function placesTxn_createFolder(aName, aContainer, aIndex,
  84.                                   aAnnotations, aChildItemsTransactions) {
  85.      return new placesCreateFolderTransactions(aName, aContainer, aIndex,
  86.                                                aAnnotations, aChildItemsTransactions);
  87.   },
  88.  
  89.   createItem:
  90.   function placesTxn_createItem(aURI, aContainer, aIndex, aTitle,
  91.                                 aKeyword, aAnnotations, aChildTransactions) {
  92.     return new placesCreateItemTransactions(aURI, aContainer, aIndex, aTitle,
  93.                                             aKeyword, aAnnotations, aChildTransactions);
  94.   },
  95.  
  96.   createSeparator:
  97.   function placesTxn_createSeparator(aContainer, aIndex) {
  98.     return new placesCreateSeparatorTransactions(aContainer, aIndex);
  99.   },
  100.  
  101.   createLivemark:
  102.   function placesTxn_createLivemark(aFeedURI, aSiteURI, aName,
  103.                                     aContainer, aIndex, aAnnotations) {
  104.     return new placesCreateLivemarkTransactions(aFeedURI, aSiteURI, aName,
  105.                                                 aContainer, aIndex, aAnnotations);
  106.   },
  107.  
  108.   moveItem:
  109.   function placesTxn_moveItem(aItemId, aNewContainer, aNewIndex) {
  110.     return new placesMoveItemTransactions(aItemId, aNewContainer, aNewIndex);
  111.   },
  112.  
  113.   removeItem:
  114.   function placesTxn_removeItem(aItemId) {
  115.     if (aItemId == PlacesUtils.tagsFolderId ||
  116.         aItemId == PlacesUtils.placesRootId ||
  117.         aItemId == PlacesUtils.bookmarksMenuFolderId ||
  118.         aItemId == PlacesUtils.toolbarFolderId)
  119.       throw Cr.NS_ERROR_INVALID_ARG;
  120.  
  121.     // if the item lives within a tag container, use the tagging transactions
  122.     var parent = PlacesUtils.bookmarks.getFolderIdForItem(aItemId);
  123.     var grandparent = PlacesUtils.bookmarks.getFolderIdForItem(parent);
  124.     if (grandparent == PlacesUtils.tagsFolderId) {
  125.       var uri = PlacesUtils.bookmarks.getBookmarkURI(aItemId);
  126.       return this.untagURI(uri, [parent]);
  127.     }
  128.     
  129.     // if the item is a livemark container we will not save its children and
  130.     // will use createLivemark to undo.
  131.     if (PlacesUtils.livemarks.isLivemark(aItemId))
  132.       return new placesRemoveLivemarkTransaction(aItemId);
  133.  
  134.     return new placesRemoveItemTransaction(aItemId);
  135.   },
  136.  
  137.   editItemTitle:
  138.   function placesTxn_editItemTitle(aItemId, aNewTitle) {
  139.     return new placesEditItemTitleTransactions(aItemId, aNewTitle);
  140.   },
  141.  
  142.   editBookmarkURI:
  143.   function placesTxn_editBookmarkURI(aItemId, aNewURI) {
  144.     return new placesEditBookmarkURITransactions(aItemId, aNewURI);
  145.   },
  146.  
  147.   setItemAnnotation:
  148.   function placesTxn_setItemAnnotation(aItemId, aAnnotationObject) {
  149.     return new placesSetItemAnnotationTransactions(aItemId, aAnnotationObject);
  150.   },
  151.  
  152.   setPageAnnotation:
  153.   function placesTxn_setPageAnnotation(aURI, aAnnotationObject) {
  154.     return new placesSetPageAnnotationTransactions(aURI, aAnnotationObject);
  155.   },
  156.  
  157.   setLoadInSidebar:
  158.   function placesTxn_setLoadInSidebar(aItemId, aLoadInSidebar) {
  159.     var annoObj = { name: LOAD_IN_SIDEBAR_ANNO,
  160.                     type: Ci.nsIAnnotationService.TYPE_INT32,
  161.                     flags: 0,
  162.                     value: aLoadInSidebar,
  163.                     expires: Ci.nsIAnnotationService.EXPIRE_NEVER };
  164.     return this.setItemAnnotation(aItemId, annoObj);
  165.   },
  166.  
  167.   editItemDescription:
  168.   function placesTxn_editItemDescription(aItemId, aDescription) {
  169.     var annoObj = { name: DESCRIPTION_ANNO,
  170.                     type: Ci.nsIAnnotationService.TYPE_STRING,
  171.                     flags: 0,
  172.                     value: aDescription,
  173.                     expires: Ci.nsIAnnotationService.EXPIRE_NEVER };
  174.     return this.setItemAnnotation(aItemId, annoObj);
  175.   },
  176.  
  177.   editBookmarkKeyword:
  178.   function placesTxn_editBookmarkKeyword(aItemId, aNewKeyword) {
  179.     return new placesEditBookmarkKeywordTransactions(aItemId, aNewKeyword);
  180.   },
  181.  
  182.   editBookmarkPostData:
  183.   function placesTxn_editBookmarkPostdata(aItemId, aPostData) {
  184.     return new placesEditBookmarkPostDataTransactions(aItemId, aPostData);
  185.   },
  186.  
  187.   editLivemarkSiteURI:
  188.   function placesTxn_editLivemarkSiteURI(aLivemarkId, aSiteURI) {
  189.     return new placesEditLivemarkSiteURITransactions(aLivemarkId, aSiteURI);
  190.   },
  191.  
  192.   editLivemarkFeedURI:
  193.   function placesTxn_editLivemarkFeedURI(aLivemarkId, aFeedURI) {
  194.     return new placesEditLivemarkFeedURITransactions(aLivemarkId, aFeedURI);
  195.   },
  196.  
  197.   editBookmarkMicrosummary:
  198.   function placesTxn_editBookmarkMicrosummary(aItemId, aNewMicrosummary) {
  199.     return new placesEditBookmarkMicrosummaryTransactions(aItemId, aNewMicrosummary);
  200.   },
  201.  
  202.   editItemDateAdded:
  203.   function placesTxn_editItemDateAdded(aItemId, aNewDateAdded) {
  204.     return new placesEditItemDateAddedTransaction(aItemId, aNewDateAdded);
  205.   },
  206.  
  207.   editItemLastModified:
  208.   function placesTxn_editItemLastModified(aItemId, aNewLastModified) {
  209.     return new placesEditItemLastModifiedTransaction(aItemId, aNewLastModified);
  210.   },
  211.  
  212.   sortFolderByName:
  213.   function placesTxn_sortFolderByName(aFolderId) {
  214.     return new placesSortFolderByNameTransactions(aFolderId);
  215.   },
  216.  
  217.   tagURI:
  218.   function placesTxn_tagURI(aURI, aTags) {
  219.     return new placesTagURITransaction(aURI, aTags);
  220.   },
  221.  
  222.   untagURI:
  223.   function placesTxn_untagURI(aURI, aTags) {
  224.     return new placesUntagURITransaction(aURI, aTags);
  225.   },
  226.  
  227.   // Update commands in the undo group of the active window
  228.   // commands in inactive windows will are updated on-focus
  229.   _updateCommands: function placesTxn__updateCommands() {
  230.     var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
  231.              getService(Ci.nsIWindowMediator);
  232.     var win = wm.getMostRecentWindow(null);
  233.     if (win)
  234.       win.updateCommands("undo");
  235.   },
  236.  
  237.   // nsITransactionManager
  238.   beginBatch: function() {
  239.     this.mTransactionManager.beginBatch();
  240.  
  241.     // A no-op transaction is pushed to the stack, in order to make safe and
  242.     // easy to implement "Undo" an unknown number of transactions (including 0),
  243.     // "above" beginBatch and endBatch. Otherwise,implementing Undo that way
  244.     // head to dataloss: for example, if no changes were done in the
  245.     // edit-item panel, the last transaction on the undo stack would be the
  246.     // initial createItem transaction, or even worse, the batched editing of
  247.     // some other item.
  248.     // DO NOT MOVE this to the window scope, that would leak (bug 490068)! 
  249.     this.doTransaction({ doTransaction: function() { },
  250.                          undoTransaction: function() { },
  251.                          redoTransaction: function() { },
  252.                          isTransient: false,
  253.                          merge: function() { return false; } });
  254.   },
  255.  
  256.   endBatch: function() this.mTransactionManager.endBatch(),
  257.  
  258.   doTransaction: function placesTxn_doTransaction(txn) {
  259.     this.mTransactionManager.doTransaction(txn);
  260.     this._updateCommands();
  261.   },
  262.  
  263.   undoTransaction: function placesTxn_undoTransaction() {
  264.     this.mTransactionManager.undoTransaction();
  265.     this._updateCommands();
  266.   },
  267.  
  268.   redoTransaction: function placesTxn_redoTransaction() {
  269.     this.mTransactionManager.redoTransaction();
  270.     this._updateCommands();
  271.   },
  272.  
  273.   clear: function() this.mTransactionManager.clear(),
  274.  
  275.   get numberOfUndoItems() {
  276.     return this.mTransactionManager.numberOfUndoItems;
  277.   },
  278.  
  279.   get numberOfRedoItems() {
  280.     return this.mTransactionManager.numberOfRedoItems;
  281.   },
  282.  
  283.   get maxTransactionCount() {
  284.     return this.mTransactionManager.maxTransactionCount;
  285.   },
  286.   set maxTransactionCount(val) {
  287.     return this.mTransactionManager.maxTransactionCount = val;
  288.   },
  289.  
  290.   peekUndoStack: function() this.mTransactionManager.peekUndoStack(),
  291.   peekRedoStack: function() this.mTransactionManager.peekRedoStack(),
  292.   getUndoStack: function() this.mTransactionManager.getUndoStack(),
  293.   getRedoStack: function() this.mTransactionManager.getRedoStack(),
  294.   AddListener: function(l) this.mTransactionManager.AddListener(l),
  295.   RemoveListener: function(l) this.mTransactionManager.RemoveListener(l)
  296. };
  297.  
  298. /**
  299.  * Method and utility stubs for Places Edit Transactions
  300.  */
  301. function placesBaseTransaction() {
  302. }
  303.  
  304. placesBaseTransaction.prototype = {
  305.   // for child-transactions
  306.   get wrappedJSObject() {
  307.     return this;
  308.   },
  309.  
  310.   // nsITransaction
  311.   redoTransaction: function PBT_redoTransaction() {
  312.     throw Cr.NS_ERROR_NOT_IMPLEMENTED;
  313.   },
  314.  
  315.   get isTransient() {
  316.     return false;
  317.   },
  318.  
  319.   merge: function mergeFunc(transaction) {
  320.     return false;
  321.   },
  322.  
  323.   // nsISupports
  324.   QueryInterface: XPCOMUtils.generateQI([Ci.nsITransaction]),
  325. };
  326.  
  327. function placesAggregateTransactions(name, transactions) {
  328.   this._transactions = transactions;
  329.   this._name = name;
  330.   this.container = -1;
  331.   this.redoTransaction = this.doTransaction;
  332. }
  333.  
  334. placesAggregateTransactions.prototype = {
  335.   __proto__: placesBaseTransaction.prototype,
  336.  
  337.   doTransaction: function PAT_doTransaction() {
  338.     if (this._transactions.length >= MIN_TRANSACTIONS_FOR_BATCH) {
  339.       var callback = {
  340.         _self: this,
  341.         runBatched: function() {
  342.           this._self.commit(false);
  343.         }
  344.       };
  345.       PlacesUtils.bookmarks.runInBatchMode(callback, null);
  346.     }
  347.     else
  348.       this.commit(false);
  349.   },
  350.  
  351.   undoTransaction: function PAT_undoTransaction() {
  352.     if (this._transactions.length >= MIN_TRANSACTIONS_FOR_BATCH) {
  353.       var callback = {
  354.         _self: this,
  355.         runBatched: function() {
  356.           this._self.commit(true);
  357.         }
  358.       };
  359.       PlacesUtils.bookmarks.runInBatchMode(callback, null);
  360.     }
  361.     else
  362.       this.commit(true);
  363.   },
  364.  
  365.   commit: function PAT_commit(aUndo) {
  366.     var transactions = this._transactions;
  367.     if (aUndo)
  368.       transactions.reverse();
  369.     for (var i = 0; i < transactions.length; i++) {
  370.       var txn = transactions[i];
  371.       if (this.container > -1) 
  372.         txn.wrappedJSObject.container = this.container;
  373.       if (aUndo)
  374.         txn.undoTransaction();
  375.       else
  376.         txn.doTransaction();
  377.     }
  378.   }
  379. };
  380.  
  381. function placesCreateFolderTransactions(aName, aContainer, aIndex,
  382.                                         aAnnotations,
  383.                                         aChildItemsTransactions) {
  384.   this._name = aName;
  385.   this._container = aContainer;
  386.   this._index = typeof(aIndex) == "number" ? aIndex : -1;
  387.   this._annotations = aAnnotations;
  388.   this._id = null;
  389.   this._childItemsTransactions = aChildItemsTransactions || [];
  390.   this.redoTransaction = this.doTransaction;
  391. }
  392.  
  393. placesCreateFolderTransactions.prototype = {
  394.   __proto__: placesBaseTransaction.prototype,
  395.  
  396.   // childItemsTransaction support
  397.   get container() { return this._container; },
  398.   set container(val) { return this._container = val; },
  399.  
  400.   doTransaction: function PCFT_doTransaction() {
  401.     this._id = PlacesUtils.bookmarks.createFolder(this._container, 
  402.                                                   this._name, this._index);
  403.     if (this._annotations && this._annotations.length > 0)
  404.       PlacesUtils.setAnnotationsForItem(this._id, this._annotations);
  405.  
  406.     for (var i = 0; i < this._childItemsTransactions.length; ++i) {
  407.       var txn = this._childItemsTransactions[i];
  408.       txn.wrappedJSObject.container = this._id;
  409.       txn.doTransaction();
  410.     }
  411.   },
  412.  
  413.   undoTransaction: function PCFT_undoTransaction() {
  414.     // Undo transactions should always be done in reverse order.
  415.     for (var i = this._childItemsTransactions.length - 1; i >= 0 ; i--) {
  416.       var txn = this._childItemsTransactions[i];
  417.       txn.undoTransaction();
  418.     }
  419.     // Remove item only after all child transactions have been reverted.
  420.     PlacesUtils.bookmarks.removeFolder(this._id);
  421.   }
  422. };
  423.  
  424. function placesCreateItemTransactions(aURI, aContainer, aIndex, aTitle,
  425.                                       aKeyword, aAnnotations,
  426.                                       aChildTransactions) {
  427.   this._uri = aURI;
  428.   this._container = aContainer;
  429.   this._index = typeof(aIndex) == "number" ? aIndex : -1;
  430.   this._title = aTitle;
  431.   this._keyword = aKeyword;
  432.   this._annotations = aAnnotations;
  433.   this._childTransactions = aChildTransactions || [];
  434.   this.redoTransaction = this.doTransaction;
  435. }
  436.  
  437. placesCreateItemTransactions.prototype = {
  438.   __proto__: placesBaseTransaction.prototype,
  439.  
  440.   // childItemsTransactions support for the create-folder transaction
  441.   get container() { return this._container; },
  442.   set container(val) { return this._container = val; },
  443.  
  444.   doTransaction: function PCIT_doTransaction() {
  445.     this._id = PlacesUtils.bookmarks.insertBookmark(this.container, this._uri,
  446.                                                     this._index, this._title);
  447.     if (this._keyword)
  448.       PlacesUtils.bookmarks.setKeywordForBookmark(this._id, this._keyword);
  449.     if (this._annotations && this._annotations.length > 0)
  450.       PlacesUtils.setAnnotationsForItem(this._id, this._annotations);
  451.  
  452.     for (var i = 0; i < this._childTransactions.length; ++i) {
  453.       var txn = this._childTransactions[i];
  454.       txn.wrappedJSObject.id = this._id;
  455.       txn.doTransaction();
  456.     }
  457.   },
  458.  
  459.   undoTransaction: function PCIT_undoTransaction() {
  460.     // Undo transactions should always be done in reverse order.
  461.     for (var i = this._childTransactions.length - 1; i >= 0; i--) {
  462.       var txn = this._childTransactions[i];
  463.       txn.undoTransaction();
  464.     }
  465.     // Remove item only after all child transactions have been reverted.
  466.     PlacesUtils.bookmarks.removeItem(this._id);
  467.   }
  468. };
  469.  
  470. function placesCreateSeparatorTransactions(aContainer, aIndex) {
  471.   this._container = aContainer;
  472.   this._index = typeof(aIndex) == "number" ? aIndex : -1;
  473.   this._id = null;
  474.   this.redoTransaction = this.doTransaction;
  475. }
  476.  
  477. placesCreateSeparatorTransactions.prototype = {
  478.   __proto__: placesBaseTransaction.prototype,
  479.  
  480.   // childItemsTransaction support
  481.   get container() { return this._container; },
  482.   set container(val) { return this._container = val; },
  483.  
  484.   doTransaction: function PCST_doTransaction() {
  485.     this._id = PlacesUtils.bookmarks
  486.                           .insertSeparator(this.container, this._index);
  487.   },
  488.  
  489.   undoTransaction: function PCST_undoTransaction() {
  490.     PlacesUtils.bookmarks.removeItem(this._id);
  491.   }
  492. };
  493.  
  494. function placesCreateLivemarkTransactions(aFeedURI, aSiteURI, aName,
  495.                                           aContainer, aIndex,
  496.                                           aAnnotations) {
  497.   this.redoTransaction = this.doTransaction;
  498.   this._feedURI = aFeedURI;
  499.   this._siteURI = aSiteURI;
  500.   this._name = aName;
  501.   this._container = aContainer;
  502.   this._index = typeof(aIndex) == "number" ? aIndex : -1;
  503.   this._annotations = aAnnotations;
  504. }
  505.  
  506. placesCreateLivemarkTransactions.prototype = {
  507.   __proto__: placesBaseTransaction.prototype,
  508.  
  509.   // childItemsTransaction support
  510.   get container() { return this._container; },
  511.   set container(val) { return this._container = val; },
  512.  
  513.   doTransaction: function PCLT_doTransaction() {
  514.     this._id = PlacesUtils.livemarks.createLivemark(this._container, this._name,
  515.                                                     this._siteURI, this._feedURI,
  516.                                                     this._index);
  517.     if (this._annotations && this._annotations.length > 0)
  518.       PlacesUtils.setAnnotationsForItem(this._id, this._annotations);
  519.   },
  520.  
  521.   undoTransaction: function PCLT_undoTransaction() {
  522.     PlacesUtils.bookmarks.removeFolder(this._id);
  523.   }
  524. };
  525.  
  526. function placesRemoveLivemarkTransaction(aFolderId) {
  527.   this.redoTransaction = this.doTransaction;
  528.   this._id = aFolderId;
  529.   this._title = PlacesUtils.bookmarks.getItemTitle(this._id);
  530.   this._container = PlacesUtils.bookmarks.getFolderIdForItem(this._id);
  531.   var annos = PlacesUtils.getAnnotationsForItem(this._id);
  532.   // Exclude livemark service annotations, those will be recreated automatically
  533.   var annosToExclude = ["livemark/feedURI",
  534.                         "livemark/siteURI",
  535.                         "livemark/expiration",
  536.                         "livemark/loadfailed",
  537.                         "livemark/loading"];
  538.   this._annotations = annos.filter(function(aValue, aIndex, aArray) {
  539.       return annosToExclude.indexOf(aValue.name) == -1;
  540.     });
  541.   this._feedURI = PlacesUtils.livemarks.getFeedURI(this._id);
  542.   this._siteURI = PlacesUtils.livemarks.getSiteURI(this._id);
  543.   this._dateAdded = PlacesUtils.bookmarks.getItemDateAdded(this._id);
  544.   this._lastModified = PlacesUtils.bookmarks.getItemLastModified(this._id);
  545. }
  546.  
  547. placesRemoveLivemarkTransaction.prototype = {
  548.   __proto__: placesBaseTransaction.prototype,
  549.  
  550.   doTransaction: function PRLT_doTransaction() {
  551.     this._index = PlacesUtils.bookmarks.getItemIndex(this._id);
  552.     PlacesUtils.bookmarks.removeItem(this._id);
  553.   },
  554.  
  555.   undoTransaction: function PRLT_undoTransaction() {
  556.     this._id = PlacesUtils.livemarks.createLivemark(this._container,
  557.                                                     this._title,
  558.                                                     this._siteURI,
  559.                                                     this._feedURI,
  560.                                                     this._index);
  561.     PlacesUtils.bookmarks.setItemDateAdded(this._id, this._dateAdded);
  562.     PlacesUtils.bookmarks.setItemLastModified(this._id, this._lastModified);
  563.     // Restore annotations
  564.     PlacesUtils.setAnnotationsForItem(this._id, this._annotations);
  565.   }
  566. };
  567.  
  568. function placesMoveItemTransactions(aItemId, aNewContainer, aNewIndex) {
  569.   this._id = aItemId;
  570.   this._oldContainer = PlacesUtils.bookmarks.getFolderIdForItem(this._id);
  571.   this._newContainer = aNewContainer;
  572.   this._newIndex = aNewIndex;
  573.   this.redoTransaction = this.doTransaction;
  574. }
  575.  
  576. placesMoveItemTransactions.prototype = {
  577.   __proto__: placesBaseTransaction.prototype,
  578.  
  579.   doTransaction: function PMIT_doTransaction() {
  580.     this._oldIndex = PlacesUtils.bookmarks.getItemIndex(this._id);
  581.     PlacesUtils.bookmarks.moveItem(this._id, this._newContainer, this._newIndex);
  582.     this._undoIndex = PlacesUtils.bookmarks.getItemIndex(this._id);
  583.   },
  584.  
  585.   undoTransaction: function PMIT_undoTransaction() {
  586.     // moving down in the same container takes in count removal of the item
  587.     // so to revert positions we must move to oldIndex + 1
  588.     if (this._newContainer == this._oldContainer &&
  589.         this._oldIndex > this._undoIndex)
  590.       PlacesUtils.bookmarks.moveItem(this._id, this._oldContainer, this._oldIndex + 1);
  591.     else
  592.       PlacesUtils.bookmarks.moveItem(this._id, this._oldContainer, this._oldIndex);
  593.   }
  594. };
  595.  
  596. function placesRemoveItemTransaction(aItemId) {
  597.   this.redoTransaction = this.doTransaction;
  598.   this._id = aItemId;
  599.   this._itemType = PlacesUtils.bookmarks.getItemType(this._id);
  600.   if (this._itemType == Ci.nsINavBookmarksService.TYPE_FOLDER) {
  601.     this._transactions = [];
  602.     this._removeTxn = PlacesUtils.bookmarks
  603.                                  .getRemoveFolderTransaction(this._id);
  604.   }
  605.   else if (this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK) {
  606.     this._uri = PlacesUtils.bookmarks.getBookmarkURI(this._id);
  607.     this._keyword = PlacesUtils.bookmarks.getKeywordForBookmark(this._id);
  608.   }
  609.  
  610.   if (this._itemType != Ci.nsINavBookmarksService.TYPE_SEPARATOR)
  611.     this._title = PlacesUtils.bookmarks.getItemTitle(this._id);
  612.  
  613.   this._oldContainer = PlacesUtils.bookmarks.getFolderIdForItem(this._id);
  614.   this._annotations = PlacesUtils.getAnnotationsForItem(this._id);
  615.   this._dateAdded = PlacesUtils.bookmarks.getItemDateAdded(this._id);
  616.   this._lastModified = PlacesUtils.bookmarks.getItemLastModified(this._id);
  617. }
  618.  
  619. placesRemoveItemTransaction.prototype = {
  620.   __proto__: placesBaseTransaction.prototype,
  621.  
  622.   doTransaction: function PRIT_doTransaction() {
  623.     this._oldIndex = PlacesUtils.bookmarks.getItemIndex(this._id);
  624.  
  625.     if (this._itemType == Ci.nsINavBookmarksService.TYPE_FOLDER) {
  626.       this._saveFolderContents();
  627.  
  628.       // Remove children backwards to preserve parent-child relationships.
  629.       for (var i = this._transactions.length - 1; i >= 0; --i)
  630.         this._transactions[i].doTransaction();
  631.     
  632.       // Remove this folder itself. 
  633.       this._removeTxn.doTransaction();
  634.     }
  635.     else {
  636.       PlacesUtils.bookmarks.removeItem(this._id);
  637.       if (this._uri) {
  638.         // if this was the last bookmark (excluding tag-items and livemark
  639.         // children, see getMostRecentBookmarkForURI) for the bookmark's url,
  640.         // remove the url from tag containers as well.
  641.         if (PlacesUtils.getMostRecentBookmarkForURI(this._uri) == -1) {
  642.           this._tags = PlacesUtils.tagging.getTagsForURI(this._uri, {});
  643.           PlacesUtils.tagging.untagURI(this._uri, this._tags);
  644.         }
  645.       }
  646.     }
  647.   },
  648.  
  649.   undoTransaction: function PRIT_undoTransaction() {
  650.     if (this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK) {
  651.       this._id = PlacesUtils.bookmarks.insertBookmark(this._oldContainer,
  652.                                                       this._uri,
  653.                                                       this._oldIndex,
  654.                                                       this._title);
  655.       if (this._tags && this._tags.length > 0)
  656.         PlacesUtils.tagging.tagURI(this._uri, this._tags);
  657.       if (this._keyword)
  658.         PlacesUtils.bookmarks.setKeywordForBookmark(this._id, this._keyword);
  659.     }
  660.     else if (this._itemType == Ci.nsINavBookmarksService.TYPE_FOLDER) {
  661.       this._removeTxn.undoTransaction();
  662.       // Create children forwards to preserve parent-child relationships.
  663.       for (var i = 0; i < this._transactions.length; ++i)
  664.         this._transactions[i].undoTransaction();
  665.     }
  666.     else // TYPE_SEPARATOR
  667.       this._id = PlacesUtils.bookmarks.insertSeparator(this._oldContainer, this._oldIndex);
  668.  
  669.     if (this._annotations.length > 0)
  670.       PlacesUtils.setAnnotationsForItem(this._id, this._annotations);
  671.  
  672.     PlacesUtils.bookmarks.setItemDateAdded(this._id, this._dateAdded);
  673.     PlacesUtils.bookmarks.setItemLastModified(this._id, this._lastModified);
  674.   },
  675.  
  676.   /**
  677.   * Create a flat, ordered list of transactions for a depth-first recreation
  678.   * of items within this folder.
  679.   */
  680.   _saveFolderContents: function PRIT__saveFolderContents() {
  681.     this._transactions = [];
  682.     var contents =
  683.       PlacesUtils.getFolderContents(this._id, false, false).root;
  684.     for (var i = 0; i < contents.childCount; ++i) {
  685.       this._transactions
  686.           .push(new placesRemoveItemTransaction(contents.getChild(i).itemId));
  687.     }
  688.   }
  689. };
  690.  
  691. function placesEditItemTitleTransactions(id, newTitle) {
  692.   this._id = id;
  693.   this._newTitle = newTitle;
  694.   this._oldTitle = "";
  695.   this.redoTransaction = this.doTransaction;
  696. }
  697.  
  698. placesEditItemTitleTransactions.prototype = {
  699.   __proto__: placesBaseTransaction.prototype,
  700.  
  701.   doTransaction: function PEITT_doTransaction() {
  702.     this._oldTitle = PlacesUtils.bookmarks.getItemTitle(this._id);
  703.     PlacesUtils.bookmarks.setItemTitle(this._id, this._newTitle);
  704.   },
  705.  
  706.   undoTransaction: function PEITT_undoTransaction() {
  707.     PlacesUtils.bookmarks.setItemTitle(this._id, this._oldTitle);
  708.   }
  709. };
  710.  
  711. function placesEditBookmarkURITransactions(aBookmarkId, aNewURI) {
  712.   this._id = aBookmarkId;
  713.   this._newURI = aNewURI;
  714.   this.redoTransaction = this.doTransaction;
  715. }
  716.  
  717. placesEditBookmarkURITransactions.prototype = {
  718.   __proto__: placesBaseTransaction.prototype,
  719.  
  720.   doTransaction: function PEBUT_doTransaction() {
  721.     this._oldURI = PlacesUtils.bookmarks.getBookmarkURI(this._id);
  722.     PlacesUtils.bookmarks.changeBookmarkURI(this._id, this._newURI);
  723.     // move tags from old URI to new URI
  724.     this._tags = PlacesUtils.tagging.getTagsForURI(this._oldURI, {});
  725.     if (this._tags.length != 0) {
  726.       // only untag the old URI if this is the only bookmark
  727.       if (PlacesUtils.getBookmarksForURI(this._oldURI, {}).length == 0)
  728.         PlacesUtils.tagging.untagURI(this._oldURI, this._tags);
  729.       PlacesUtils.tagging.tagURI(this._newURI, this._tags);
  730.     }
  731.   },
  732.  
  733.   undoTransaction: function PEBUT_undoTransaction() {
  734.     PlacesUtils.bookmarks.changeBookmarkURI(this._id, this._oldURI);
  735.     // move tags from new URI to old URI 
  736.     if (this._tags.length != 0) {
  737.       // only untag the new URI if this is the only bookmark
  738.       if (PlacesUtils.getBookmarksForURI(this._newURI, {}).length == 0)
  739.         PlacesUtils.tagging.untagURI(this._newURI, this._tags);
  740.       PlacesUtils.tagging.tagURI(this._oldURI, this._tags);
  741.     }
  742.   }
  743. };
  744.  
  745. function placesSetItemAnnotationTransactions(aItemId, aAnnotationObject) {
  746.   this.id = aItemId;
  747.   this._anno = aAnnotationObject;
  748.   // create an empty old anno
  749.   this._oldAnno = { name: this._anno.name,
  750.                     type: Ci.nsIAnnotationService.TYPE_STRING,
  751.                     flags: 0,
  752.                     value: null,
  753.                     expires: Ci.nsIAnnotationService.EXPIRE_NEVER };
  754.   this.redoTransaction = this.doTransaction;
  755. }
  756.  
  757. placesSetItemAnnotationTransactions.prototype = {
  758.   __proto__: placesBaseTransaction.prototype,
  759.  
  760.   doTransaction: function PSIAT_doTransaction() {
  761.     // Since this can be used as a child transaction this.id will be known
  762.     // only at this point, after the external caller has set it.
  763.     if (PlacesUtils.annotations.itemHasAnnotation(this.id, this._anno.name)) {
  764.       // Save the old annotation if it is set.
  765.       var flags = {}, expires = {}, mimeType = {}, type = {};
  766.       PlacesUtils.annotations.getItemAnnotationInfo(this.id, this._anno.name,
  767.                                                     flags, expires, mimeType,
  768.                                                     type);
  769.       this._oldAnno.flags = flags.value;
  770.       this._oldAnno.expires = expires.value;
  771.       this._oldAnno.mimeType = mimeType.value;
  772.       this._oldAnno.type = type.value;
  773.       this._oldAnno.value = PlacesUtils.annotations
  774.                                        .getItemAnnotation(this.id,
  775.                                                           this._anno.name);
  776.     }
  777.  
  778.     PlacesUtils.setAnnotationsForItem(this.id, [this._anno]);
  779.   },
  780.  
  781.   undoTransaction: function PSIAT_undoTransaction() {
  782.     PlacesUtils.setAnnotationsForItem(this.id, [this._oldAnno]);
  783.   }
  784. };
  785.  
  786. function placesSetPageAnnotationTransactions(aURI, aAnnotationObject) {
  787.   this._uri = aURI;
  788.   this._anno = aAnnotationObject;
  789.   // create an empty old anno
  790.   this._oldAnno = { name: this._anno.name,
  791.                     type: Ci.nsIAnnotationService.TYPE_STRING,
  792.                     flags: 0,
  793.                     value: null,
  794.                     expires: Ci.nsIAnnotationService.EXPIRE_NEVER };
  795.  
  796.   if (PlacesUtils.annotations.pageHasAnnotation(this._uri, this._anno.name)) {
  797.     // fill the old anno if it is set
  798.     var flags = {}, expires = {}, mimeType = {}, type = {};
  799.     PlacesUtils.annotations.getPageAnnotationInfo(this._uri, this._anno.name,
  800.                                                   flags, expires, mimeType, type);
  801.     this._oldAnno.flags = flags.value;
  802.     this._oldAnno.expires = expires.value;
  803.     this._oldAnno.mimeType = mimeType.value;
  804.     this._oldAnno.type = type.value;
  805.     this._oldAnno.value = PlacesUtils.annotations
  806.                                      .getPageAnnotation(this._uri, this._anno.name);
  807.   }
  808.  
  809.   this.redoTransaction = this.doTransaction;
  810. }
  811.  
  812. placesSetPageAnnotationTransactions.prototype = {
  813.   __proto__: placesBaseTransaction.prototype,
  814.  
  815.   doTransaction: function PSPAT_doTransaction() {
  816.     PlacesUtils.setAnnotationsForURI(this._uri, [this._anno]);
  817.   },
  818.  
  819.   undoTransaction: function PSPAT_undoTransaction() {
  820.     PlacesUtils.setAnnotationsForURI(this._uri, [this._oldAnno]);
  821.   }
  822. };
  823.  
  824. function placesEditBookmarkKeywordTransactions(id, newKeyword) {
  825.   this.id = id;
  826.   this._newKeyword = newKeyword;
  827.   this._oldKeyword = "";
  828.   this.redoTransaction = this.doTransaction;
  829. }
  830.  
  831. placesEditBookmarkKeywordTransactions.prototype = {
  832.   __proto__: placesBaseTransaction.prototype,
  833.  
  834.   doTransaction: function PEBKT_doTransaction() {
  835.     this._oldKeyword = PlacesUtils.bookmarks.getKeywordForBookmark(this.id);
  836.     PlacesUtils.bookmarks.setKeywordForBookmark(this.id, this._newKeyword);
  837.   },
  838.  
  839.   undoTransaction: function PEBKT_undoTransaction() {
  840.     PlacesUtils.bookmarks.setKeywordForBookmark(this.id, this._oldKeyword);
  841.   }
  842. };
  843.  
  844. function placesEditBookmarkPostDataTransactions(aItemId, aPostData) {
  845.   this.id = aItemId;
  846.   this._newPostData = aPostData;
  847.   this._oldPostData = null;
  848.   this.redoTransaction = this.doTransaction;
  849. }
  850.  
  851. placesEditBookmarkPostDataTransactions.prototype = {
  852.   __proto__: placesBaseTransaction.prototype,
  853.  
  854.   doTransaction: function PEUPDT_doTransaction() {
  855.     this._oldPostData = PlacesUtils.getPostDataForBookmark(this.id);
  856.     PlacesUtils.setPostDataForBookmark(this.id, this._newPostData);
  857.   },
  858.  
  859.   undoTransaction: function PEUPDT_undoTransaction() {
  860.     PlacesUtils.setPostDataForBookmark(this.id, this._oldPostData);
  861.   }
  862. };
  863.  
  864. function placesEditLivemarkSiteURITransactions(folderId, uri) {
  865.   this._folderId = folderId;
  866.   this._newURI = uri;
  867.   this._oldURI = null;
  868.   this.redoTransaction = this.doTransaction;
  869. }
  870.  
  871. placesEditLivemarkSiteURITransactions.prototype = {
  872.   __proto__: placesBaseTransaction.prototype,
  873.  
  874.   doTransaction: function PELSUT_doTransaction() {
  875.     this._oldURI = PlacesUtils.livemarks.getSiteURI(this._folderId);
  876.     PlacesUtils.livemarks.setSiteURI(this._folderId, this._newURI);
  877.   },
  878.  
  879.   undoTransaction: function PELSUT_undoTransaction() {
  880.     PlacesUtils.livemarks.setSiteURI(this._folderId, this._oldURI);
  881.   }
  882. };
  883.  
  884. function placesEditLivemarkFeedURITransactions(folderId, uri) {
  885.   this._folderId = folderId;
  886.   this._newURI = uri;
  887.   this._oldURI = null;
  888.   this.redoTransaction = this.doTransaction;
  889. }
  890.  
  891. placesEditLivemarkFeedURITransactions.prototype = {
  892.   __proto__: placesBaseTransaction.prototype,
  893.  
  894.   doTransaction: function PELFUT_doTransaction() {
  895.     this._oldURI = PlacesUtils.livemarks.getFeedURI(this._folderId);
  896.     PlacesUtils.livemarks.setFeedURI(this._folderId, this._newURI);
  897.     PlacesUtils.livemarks.reloadLivemarkFolder(this._folderId);
  898.   },
  899.  
  900.   undoTransaction: function PELFUT_undoTransaction() {
  901.     PlacesUtils.livemarks.setFeedURI(this._folderId, this._oldURI);
  902.     PlacesUtils.livemarks.reloadLivemarkFolder(this._folderId);
  903.   }
  904. };
  905.  
  906. function placesEditBookmarkMicrosummaryTransactions(aItemId, newMicrosummary) {
  907.   this.id = aItemId;
  908.   this._mss = Cc["@mozilla.org/microsummary/service;1"].
  909.               getService(Ci.nsIMicrosummaryService);
  910.   this._newMicrosummary = newMicrosummary;
  911.   this._oldMicrosummary = null;
  912.   this.redoTransaction = this.doTransaction;
  913. }
  914.  
  915. placesEditBookmarkMicrosummaryTransactions.prototype = {
  916.   __proto__: placesBaseTransaction.prototype,
  917.  
  918.   doTransaction: function PEBMT_doTransaction() {
  919.     this._oldMicrosummary = this._mss.getMicrosummary(this.id);
  920.     if (this._newMicrosummary)
  921.       this._mss.setMicrosummary(this.id, this._newMicrosummary);
  922.     else
  923.       this._mss.removeMicrosummary(this.id);
  924.   },
  925.  
  926.   undoTransaction: function PEBMT_undoTransaction() {
  927.     if (this._oldMicrosummary)
  928.       this._mss.setMicrosummary(this.id, this._oldMicrosummary);
  929.     else
  930.       this._mss.removeMicrosummary(this.id);
  931.   }
  932. };
  933.  
  934. function placesEditItemDateAddedTransaction(id, newDateAdded) {
  935.   this.id = id;
  936.   this._newDateAdded = newDateAdded;
  937.   this._oldDateAdded = null;
  938.   this.redoTransaction = this.doTransaction;
  939. }
  940.  
  941. placesEditItemDateAddedTransaction.prototype = {
  942.   __proto__: placesBaseTransaction.prototype,
  943.  
  944.   // to support folders as well
  945.   get container() { return this.id; },
  946.   set container(val) { return this.id = val; },
  947.  
  948.   doTransaction: function PEIDA_doTransaction() {
  949.     this._oldDateAdded = PlacesUtils.bookmarks.getItemDateAdded(this.id);
  950.     PlacesUtils.bookmarks.setItemDateAdded(this.id, this._newDateAdded);
  951.   },
  952.  
  953.   undoTransaction: function PEIDA_undoTransaction() {
  954.     PlacesUtils.bookmarks.setItemDateAdded(this.id, this._oldDateAdded);
  955.   }
  956. };
  957.  
  958. function placesEditItemLastModifiedTransaction(id, newLastModified) {
  959.   this.id = id;
  960.   this._newLastModified = newLastModified;
  961.   this._oldLastModified = null;
  962.   this.redoTransaction = this.doTransaction;
  963. }
  964.  
  965. placesEditItemLastModifiedTransaction.prototype = {
  966.   __proto__: placesBaseTransaction.prototype,
  967.  
  968.   // to support folders as well
  969.   get container() { return this.id; },
  970.   set container(val) { return this.id = val; },
  971.  
  972.   doTransaction: function PEILM_doTransaction() {
  973.     this._oldLastModified = PlacesUtils.bookmarks.getItemLastModified(this.id);
  974.     PlacesUtils.bookmarks.setItemLastModified(this.id, this._newLastModified);
  975.   },
  976.  
  977.   undoTransaction: function PEILM_undoTransaction() {
  978.     PlacesUtils.bookmarks.setItemLastModified(this.id, this._oldLastModified);
  979.   }
  980. };
  981.  
  982. function placesSortFolderByNameTransactions(aFolderId) {
  983.   this._folderId = aFolderId;
  984.   this._oldOrder = null,
  985.   this.redoTransaction = this.doTransaction;
  986. }
  987.  
  988. placesSortFolderByNameTransactions.prototype = {
  989.   __proto__: placesBaseTransaction.prototype,
  990.  
  991.   doTransaction: function PSSFBN_doTransaction() {
  992.     this._oldOrder = [];
  993.  
  994.     var contents = PlacesUtils.getFolderContents(this._folderId, false, false).root;
  995.     var count = contents.childCount;
  996.  
  997.     // sort between separators
  998.     var newOrder = []; 
  999.     var preSep = []; // temporary array for sorting each group of items
  1000.     var sortingMethod =
  1001.       function (a, b) {
  1002.         if (PlacesUtils.nodeIsContainer(a) && !PlacesUtils.nodeIsContainer(b))
  1003.           return -1;
  1004.         if (!PlacesUtils.nodeIsContainer(a) && PlacesUtils.nodeIsContainer(b))
  1005.           return 1;
  1006.         return a.title.localeCompare(b.title);
  1007.       };
  1008.  
  1009.     for (var i = 0; i < count; ++i) {
  1010.       var item = contents.getChild(i);
  1011.       this._oldOrder[item.itemId] = i;
  1012.       if (PlacesUtils.nodeIsSeparator(item)) {
  1013.         if (preSep.length > 0) {
  1014.           preSep.sort(sortingMethod);
  1015.           newOrder = newOrder.concat(preSep);
  1016.           preSep.splice(0);
  1017.         }
  1018.         newOrder.push(item);
  1019.       }
  1020.       else
  1021.         preSep.push(item);
  1022.     }
  1023.     if (preSep.length > 0) {
  1024.       preSep.sort(sortingMethod);
  1025.       newOrder = newOrder.concat(preSep);
  1026.     }
  1027.  
  1028.     // set the nex indexes
  1029.     var callback = {
  1030.       runBatched: function() {
  1031.         for (var i = 0; i < newOrder.length; ++i) {
  1032.           PlacesUtils.bookmarks.setItemIndex(newOrder[i].itemId, i);
  1033.         }
  1034.       }
  1035.     };
  1036.     PlacesUtils.bookmarks.runInBatchMode(callback, null);
  1037.   },
  1038.  
  1039.   undoTransaction: function PSSFBN_undoTransaction() {
  1040.     var callback = {
  1041.       _self: this,
  1042.       runBatched: function() {
  1043.         for (item in this._self._oldOrder)
  1044.           PlacesUtils.bookmarks.setItemIndex(item, this._self._oldOrder[item]);
  1045.       }
  1046.     };
  1047.     PlacesUtils.bookmarks.runInBatchMode(callback, null);
  1048.   }
  1049. };
  1050.  
  1051. function placesTagURITransaction(aURI, aTags) {
  1052.   this._uri = aURI;
  1053.   this._tags = aTags;
  1054.   this._unfiledItemId = -1;
  1055.   this.redoTransaction = this.doTransaction;
  1056. }
  1057.  
  1058. placesTagURITransaction.prototype = {
  1059.   __proto__: placesBaseTransaction.prototype,
  1060.  
  1061.   doTransaction: function PTU_doTransaction() {
  1062.     if (PlacesUtils.getMostRecentBookmarkForURI(this._uri) == -1) {
  1063.       // Force an unfiled bookmark first
  1064.       this._unfiledItemId =
  1065.         PlacesUtils.bookmarks
  1066.                    .insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
  1067.                                    this._uri,
  1068.                                    PlacesUtils.bookmarks.DEFAULT_INDEX,
  1069.                                    PlacesUtils.history.getPageTitle(this._uri));
  1070.     }
  1071.     PlacesUtils.tagging.tagURI(this._uri, this._tags);
  1072.   },
  1073.  
  1074.   undoTransaction: function PTU_undoTransaction() {
  1075.     if (this._unfiledItemId != -1) {
  1076.       PlacesUtils.bookmarks.removeItem(this._unfiledItemId);
  1077.       this._unfiledItemId = -1;
  1078.     }
  1079.     PlacesUtils.tagging.untagURI(this._uri, this._tags);
  1080.   }
  1081. };
  1082.  
  1083. function placesUntagURITransaction(aURI, aTags) {
  1084.   this._uri = aURI;
  1085.   if (aTags) {    
  1086.     // Within this transaction, we cannot rely on tags given by itemId
  1087.     // since the tag containers may be gone after we call untagURI.
  1088.     // Thus, we convert each tag given by its itemId to name.
  1089.     this._tags = aTags;
  1090.     for (var i=0; i < aTags.length; i++) {
  1091.       if (typeof(this._tags[i]) == "number")
  1092.         this._tags[i] = PlacesUtils.bookmarks.getItemTitle(this._tags[i]);
  1093.     }
  1094.   }
  1095.   else
  1096.     this._tags = PlacesUtils.tagging.getTagsForURI(this._uri, {});
  1097.  
  1098.   this.redoTransaction = this.doTransaction;
  1099. }
  1100.  
  1101. placesUntagURITransaction.prototype = {
  1102.   __proto__: placesBaseTransaction.prototype,
  1103.  
  1104.   doTransaction: function PUTU_doTransaction() {
  1105.     PlacesUtils.tagging.untagURI(this._uri, this._tags);
  1106.   },
  1107.  
  1108.   undoTransaction: function PUTU_undoTransaction() {
  1109.     PlacesUtils.tagging.tagURI(this._uri, this._tags);
  1110.   }
  1111. };
  1112.  
  1113.  
  1114. function NSGetModule(aCompMgr, aFileSpec) {
  1115.   return XPCOMUtils.generateModule([placesTransactionsService]);
  1116. }
  1117.